<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
        "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xml:lang="en" xmlns="http://www.w3.org/1999/xhtml">
<head>
  <title>areaDetector Plugin NDPluginROIStat</title>
  <meta content="text/html; charset=ISO-8859-1" http-equiv="Content-Type" />
</head>
<body>
  <div style="text-align: center">
    <h1>
      areaDetector Plugin NDPluginTimeSeries</h1>
    <h2>
      March 18, 2016</h2>
    <h2>
      Mark Rivers</h2>
    <h2>
      University of Chicago</h2>
  </div>
  <h2>
    Contents</h2>
  <ul>
    <li><a href="#Overview">Overview</a></li>
    <li><a href="#Configuration">Configuration</a></li>
    <li><a href="#Screens">Screen shots</a></li>
  </ul>
  <h2 id="Overview">
    Overview
  </h2>
  <p>
    This plugin accepts 1-D arrays of dimension [NumSignals] or 2-D arrays of dimension
    [NumSignals, NewTimePoints]. The plugin creates NumSignals NDArrays of dimension
    [NumTimePoints], each of which is the time-series for one signal. It also creates
    an NDArray of dimension [NumTimePoints, NumSignals] containing the data for all
    of the signals. It also exports waveform records containing the time-series data
    for each signal, and a time-axis array containing the relative times of each point
    in the time-series. These waveform records are useful for plotting in OPI screens.</p>
  <p>
    On each callback the new time points are appended to the existing time series arrays.
    The plugin can operate either two modes. In fixed time mode the time-series arrays
    are cleared when acquisition is started, and new time points are appended until
    NumTimePoints points have been received, at which point acquisition stops and further
    callbacks are ignored. In circular buffer mode once NumTimePoints samples are received
    then acquisition continues with the new time points replacing the oldest ones in
    the circular buffer.</p>
  <p>
    The plugin requires knowing the time interval between samples from the driver (TimePerPoint).
    This information normally comes from a database link to a record in the detector
    driver, but it can be manually specified as well. The plugin exports a 1-D waveform
    record containing the relative time values of each sample, which can be used for
    the horizontal axis in an OPI display.
  </p>
  <p>
    The plugin optionally does time averaging of the input signal. It can average any
    integer number of input samples(NumAverage), so that the time between points in
    the output waveforms is NumAverage*TimePerPoint = AveragingTime.</p>
  <p>
    NDPluginTimeSeries inherits from NDPluginDriver. The <a href="areaDetectorDoxygenHTML/class_n_d_plugin_time_series.html">
      NDPluginTimeSeries class documentation</a> describes this class in detail.</p>
  <p>
    Several database template files are provided:
  </p>
  <table border="1" cellpadding="2" cellspacing="2" style="text-align: left">
    <tbody>
      <tr>
        <th>
          Template File Name</th>
        <th>
          Description</th>
      </tr>
      <tr>
        <td>
          NDTimeSeries.template</td>
        <td>
          This needs to be instantiated once for each instance of the plugin. It provides
          records that apply to the entire plugin or to all signals.</td>
      </tr>
      <tr>
        <td>
          NDTimeSeriesN.template</td>
        <td>
          This needs to be instantiated once for each signal in the plugin (the number must
          equal the number of signals specified in the IOC shell function). The template provides
          records that apply to each signal.</td>
      </tr>
    </tbody>
  </table>
  <p>
    NDPluginTimeSeries inherits from NDPluginDriver.</p>
  <p>
    NDPluginTimeSeries defines the following parameters. It also implements all of the
    standard plugin parameters from <a href="pluginDoc.html#NDPluginDriver">NDPluginDriver</a>.
    The template files listed above provide access to these parameters, listed in the
    following tables.
  </p>
  <table border="1" cellpadding="2" cellspacing="2" style="text-align: left">
    <tbody>
      <tr>
        <td align="center" colspan="7">
          <b>Parameters for entire plugin.
            <br />
            Parameter Definitions in NDPluginTimeSeries.h and EPICS Record Definitions in NDTimeSeries.template</b>
        </td>
      </tr>
      <tr>
        <th>
          Parameter index variable</th>
        <th>
          asyn interface</th>
        <th>
          Access</th>
        <th>
          Description</th>
        <th>
          drvInfo string</th>
        <th>
          EPICS record name</th>
        <th>
          EPICS record type</th>
      </tr>
      <tr>
        <td>
          TSAcquire</td>
        <td>
          asynInt32</td>
        <td>
          r/w</td>
        <td>
          Starts and stops time-series data collection. Value are:
          <br />
          0: "Done": Stops times-series data collection. Performs callbacks on all time-series
          waveform records. The record automatically goes to Done when acquisition completes
          in Fixed Length acquire mode.<br />
          1: "Acquire": Clears all time-series arrays, sets TS_CURRENT_POINT=0, and starts
          time-series data collection. </td>
        <td>
          TS_ACQUIRE</td>
        <td>
          $(P)$(R)TSAcquire<br />
          $(P)$(R)TSAcquiring</td>
        <td>
          busy<br />
          bi</td>
      </tr>
      <tr>
        <td>
          TSRead</td>
        <td>
          asynInt32</td>
        <td>
          r/w</td>
        <td>
          Forces the plugin to do callbacks with the time series NDArrays and waveform records.
          This record SCAN field can be set to periodically update the waveforms. The callbacks
          are automatically done when TSAcquire goes to done at the end of acquisition in
          Fixed Length mode. </td>
        <td>
          TS_READ</td>
        <td>
          $(P)$(R)TSRead</td>
        <td>
          bo</td>
      </tr>
      <tr>
        <td>
          TSNumPoints</td>
        <td>
          asynInt32</td>
        <td>
          r/w</td>
        <td>
          Controls the number of time-series points to collect. There is no maximum value,
          the time-series arrays in the plugin are freed and reallocated each time this value
          is changed. However, the size of the waveform records is fixed when the IOC is started,
          so NELM in those records must be large enough for the largest time-series needed.
        </td>
        <td>
          TS_NUM_POINTS</td>
        <td>
          $(P)$(R)TSNumPoints</td>
        <td>
          longout</td>
      </tr>
      <tr>
        <td>
          TSCurrentPoint</td>
        <td>
          asynInt32</td>
        <td>
          r/o</td>
        <td>
          The current time-series point. In Fixed Length mode when TSCurrentPoint reaches
          TSNumPoints then time-series acquisition is automatically stopped, and callbacks
          are done on all time-series NDArrays and waveform records, updating the values.
          This means that even if TSRead.SCAN is Passive that the NDArrays and waveform records
          will update when time-series acquisition is complete. </td>
        <td>
          TS_CURRENT_POINT</td>
        <td>
          $(P)$(R)TSCurrentPoint</td>
        <td>
          longin</td>
      </tr>
      <tr>
        <td>
          TSAcquireMode</td>
        <td>
          asynInt32</td>
        <td>
          r/w</td>
        <td>
          The time series acquisition mode. Choices are:<br />
          0: "Fixed length"
          <br />
          1: "Circ. buffer" </td>
        <td>
          TS_ACQUIRE_MODE</td>
        <td>
          $(P)$(R)TSAcquireMode<br />
          $(P)$(R)TSAcquireMode_RBV</td>
        <td>
          mbbo
          <br />
          mbbi</td>
      </tr>
      <tr>
        <td>
          TSTimePerPoint</td>
        <td>
          asynFloat64</td>
        <td>
          r/w</td>
        <td>
          The time interval between samples in the waveforms from the driver. This value is
          normally updated automatically using the TSTimePerPointLink record described below.
          It can also be manually changed if there is no EPICS record available to provide
          this value automatically. This value is used to compute NumAverage, and to construct
          the TSTimeAxis array.</td>
        <td>
          TS_TIME_PER_POINT</td>
        <td>
          $(P)$(R)TSTimePerPoint<br />
          $(P)$(R)TSTimePerPoint_RBV</td>
        <td>
          ao<br />
          ai</td>
      </tr>
      <tr>
        <td>
          N.A</td>
        <td>
          N.A.</td>
        <td>
          r/w</td>
        <td>
          This record has OMSL="closed_loop" and DOL set to a record that contains the time
          between points from the driver. The link will normally have the CP attribute, so
          this record processes whenever the input record changes. The OUT field of this record
          is TSTimePerPoint.</td>
        <td>
          N.A.</td>
        <td>
          $(P)$(R)TSTimePerPointLink</td>
        <td>
          ao</td>
      </tr>
      <tr>
        <td>
          TSAveragingTime</td>
        <td>
          asynFloat64</td>
        <td>
          r/w</td>
        <td>
          The requested value of the time interval over which input time-series points are
          averaged. If the TSAveragingTime is not an integer multiple of TSTimePerPoint then
          TSAveragingTime_RBV will be different from TSAveragingTime and will be the actual
          averaging time.</td>
        <td>
          TS_AVERAGING_TIME</td>
        <td>
          $(P)$(R)TSAveragingTime<br />
          $(P)$(R)TSAveragingTime_RBV</td>
        <td>
          ao<br />
          ai</td>
      </tr>
      <tr>
        <td>
          TSNumAverage</td>
        <td>
          asynInt32</td>
        <td>
          r/o</td>
        <td>
          The number of time points from the driver that will be averaged in the plugin. This
          is computed from TSAveragingTime/TSTimePerPoint. It is constrained to be the nearest
          positive integer to this ratio.</td>
        <td>
          TS_NUM_AVERAGE</td>
        <td>
          $(P)$(R)TSNumAverage</td>
        <td>
          longin</td>
      </tr>
      <tr>
        <td>
          TSElapsedTime</td>
        <td>
          asynFloat64</td>
        <td>
          r/w</td>
        <td>
          The elapsed time since TSAcquire was set to 1. Stops updating when TSAcquire goes
          to 0.</td>
        <td>
          TS_ELAPSED_TIME</td>
        <td>
          $(P)$(R)TSElapsedTime</td>
        <td>
          ai</td>
      </tr>
      <tr>
        <td>
          TSTimeAxis</td>
        <td>
          asynFloat64ArrayIn</td>
        <td>
          r/o</td>
        <td>
          A waveform record containing the time value of each point in the TimeSeries waveforms.<br />
          When AcquireMode=&quot;Fixed length&quot; then time=0 is the time when acquisition
          started and
          <br />
          <code>TSTimeAxis[i] = TSAveragingTime_RBV * i.</code>
          <br />
          When AcquireMode=&quot;Circ. buffer&quot; then time=0 is the most recent time and
          <br />
          <code>TSTimeAxis[i] = -TSAveragingTime_RBV * (NumTimePoints-1-i)</code><br />
          so the oldest time point is the most negative.</td>
        <td>
          TS_TIME_AXIS</td>
        <td>
          $(P)$(R)TSTimeAxis</td>
        <td>
          waveform</td>
      </tr>
      <tr>
        <td>
          TSTimeStamp</td>
        <td>
          asynFloat64ArrayIn</td>
        <td>
          r/o</td>
        <td>
          A waveform record containing the NDArray timestamp for each sample from the input
          NDArray. Note that since multiple time points can be contained in a single NDArray
          there can be repeated values in this waveform. Assuming the driver provides a reliable
          value for TSTimePerPoint described above, then the TSTimeAxis waveform provides
          a more accurate relative time array to use in plotting. The values in this waveform
          are absolute timestamps which can also be useful.</td>
        <td>
          TS_TIMESTAMP</td>
        <td>
          $(P)$(R)TSTimestamp</td>
        <td>
          waveform</td>
      </tr>
    </tbody>
  </table>
  <p>
    <br />
  </p>
  <table border="1" cellpadding="2" cellspacing="2" style="text-align: left">
    <tbody>
      <tr>
        <td align="center" colspan="7">
          <b>Parameters for each signal N.
            <br />
            Parameter Definitions in NDPluginTimeSeries.h and EPICS Record Definitions in NDTimeSeriesN.template</b>
        </td>
      </tr>
      <tr>
        <th>
          Parameter index variable</th>
        <th>
          asyn interface</th>
        <th>
          Access</th>
        <th>
          Description</th>
        <th>
          drvInfo string</th>
        <th>
          EPICS record name</th>
        <th>
          EPICS record type</th>
      </tr>
      <tr>
        <td>
          TSSignalName</td>
        <td>
          N.A.</td>
        <td>
          r/w</td>
        <td>
          The name for this signal.</td>
        <td>
          N.A.</td>
        <td>
          $(P)$(R)SignalName</td>
        <td>
          stringout</td>
      </tr>
      <tr>
        <td>
          TSTimeSeries</td>
        <td>
          asynFloat64ArrayIn</td>
        <td>
          r/o</td>
        <td>
          The time series data arrays. </td>
        <td>
          TS_TIME_SERIES </td>
        <td>
          $(P)$(R)TimeSeries</td>
        <td>
          waveform</td>
      </tr>
    </tbody>
  </table>
  <h2 id="Configuration">
    Configuration</h2>
  <p>
    The NDPluginTimeSeries plugin is created with the NDTimeSeriesConfigure function,
    either from C/C++ or from the EPICS IOC shell.</p>
  <pre>NDTimeSeriesConfigure(const char *portName, int queueSize, int blockingCallbacks, 
                          const char *NDArrayPort, int NDArrayAddr, int maxSignals,
                          int maxBuffers,  size_t maxMemory, int priority, int stackSize)
  </pre>
  <p>
    All but the <code>maxSignals</code> parameter are common to all plugins.</p>
  <p>
    maxSignals defines how many signals this plugin will deal with. Usually this will
    match the number of NDTimeSeriesN templates have been loaded.</p>
  <p>
    For example:
    <br />
    <code>NDTimeSeriesConfigure("TS1", 100, 0, "DET1", 0, 8, 0, 0, 0, 0)</code>
  </p>
  <h2 id="Screens">
    Screen shots</h2>
  <p>
    The following MEDM screen provides access to the parameters in NDPluginDriver.h
    and NDPluginTimeSeries.h through records in NDPluginBase.template, and NDTimeSeries.template.
  </p>
  <div style="text-align: center">
    <h3>
      NDPluginTimeSeries.adl</h3>
    <img alt="NDPluginTimeSeries.png" src="NDPluginTimeSeries.png" />
  </div>
  <p>
    The following MEDM screen shows the time series plot for an array in NDPluginTimeSeriesN.template.
  </p>
  <div style="text-align: center">
    <h3>
      Time-series plot</h3>
    <img alt="NDTimeSeriesPlot.png" src="NDTimeSeriesPlot.png" />
  </div>
</body>
</html>
